{***************************************************************
    SpyGestion  Copyright (C) 2008 Christophe KOALI <nature2gas@gmail.com>
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
****************************************************************}
unit modApercuMsg;

interface

uses Classes,
     modBaseType,
     modLanguageParsing,
     SysUtils;


type


(*
   TAppMessageDejaAverti = record
       // On se base sur ces 4 champs pour assurer l'unicité
       Depart: TPlanetLocation;
       Arrivee: TPlanetLocation;
       NbVaisseau: integer;
       VaisseauxStr: string;


       // Autre champs:
       MsgStr        : string;


       NbAffichageMsg: integer;    // Nombre de fois que le popup d'alerte s'est affiché
       DateLastAffichage: int64;
       HaveBeenAverti: boolean;    // L'utilisateur a t-il bien vu le popup ? (en cliquant dessus)
   end;

    PAppMessageDejaAverti = ^TAppMessageDejaAverti;
*)


   TAppMessage = record
      Duree: integer;

      // date impact du serveur (correspond au champs "star" dans la page web)
      // il semble que c'est l'heure d'impact sur le serveur
      // qui n'est pas deduite de Duree
      DateImpact: int64;

      Ordre: TOGOrdre;

      Direction: TOGDirection;

      // True si le message est en rouge, False sinon
      // On peut utiliser bOwnFlotte combiner à l'ordre pour définir si c'est une menace
      bColorMenace: boolean;

      // Mouvement de ses propres flottes (généralement toujours le cas)
      bOwnFlotte: boolean;


      // Si c'est une autre personne que soi-même
      PlayerFlotte: string;


      // Planete de départ (coordonnée de l'ennemi en cas d'attaque)
      Depart: TPlanetLocation;
      DepartStr: string;

      // Planète d'arrivée
      Arrivee: TPlanetLocation;
      ArriveeStr: string;

      // -1 si impossible à déterminer
      NbVaisseau: integer;

      // Vide si impossible à déterminer
      // Permet de savoir exactement les type de vaisseaux (et distinguer les sondes des VB)
      VaisseauxStr: string;

      // Message tel quel pour une gestion par un humain
      Msg: string;
   end;


    PAppMessage = ^TAppMessage;

(*
    TCollectionAppMessageDejaAverti = class(TList)
    private
       {--------------------------------------------------}
       {Elements spécialisés de la classes}


       
       {--------------------------------------------------}
       {Gestion des pointeurs}
       // Utilisé pour la propriété Itemx
       function GetItemx(Index: integer): TAppMessageDejaAverti;
    public
       function AlreadyExists(Element: TAppMessageDejaAverti): boolean; overload;
       function AlreadyExists(Element: PAppMessage): boolean; overload;





       {--------------------------------------------------}
       {Gestion des pointeurs}
       // *** Ajout de pointeurs
       // Renvoi le pointeur de l'élément ajouté
       function Add(Element: TAppMessageDejaAverti): PAppMessageDejaAverti;
      
       // Simple ajout de pointeur
       procedure SimpleAdd(Pointeur: PAppMessageDejaAverti);
      
       // Renvoi le pointeur de l'élément ajouté/modifié
       // Utilise Get_Index pour vérifier si l'élément doit être mis à jour
       function Add_Update(Element: TAppMessageDejaAverti): PAppMessageDejaAverti;

      
       // *** Suppression de pointeur
       // Libère et supprime le pointeur Index
       // Renvoi True si réussit, False si hors limite ou erreur
       function Delete(Index: integer): boolean; overload;

       // Cherche Element avec Get_Index et supprime LE
       // PREMIER pointeur trouvé, renvoi True si réussit
       function Delete(Element: string): boolean; overload;

      
       // *** Effacement de la liste de pointeur
       procedure Clear; override;
      
      
       // *** Requete sur la liste de pointeur
       function Get_Index(const Element: string): integer;
       function Get_Pointeur(const Element: string): PAppMessageDejaAverti;
       function Get_Item(Index: integer): TAppMessageDejaAverti;
       property Itemx[Index: integer]: TAppMessageDejaAverti read GetItemx;
      

      
       {--------------------------------------------------}
       {Procédures et fonctions spécialisées de la classes}
       // Destructeur
       destructor Destroy; override;
       constructor Create;


    end;
*)


    TCollectionAppMessage = class(TList)
    private
       {--------------------------------------------------}
       {Elements spécialisés de la classes}


      
       {--------------------------------------------------}
       {Gestion des pointeurs}
       // Utilisé pour la propriété Itemx
       function GetItemx(Index: integer): TAppMessage;
    public


       {--------------------------------------------------}
       {Gestion des pointeurs}
       // *** Ajout de pointeurs
       // Renvoi le pointeur de l'élément ajouté
       function Add(Element: TAppMessage): PAppMessage;
      
       // Simple ajout de pointeur
       procedure SimpleAdd(Pointeur: PAppMessage);
      
       // Renvoi le pointeur de l'élément ajouté/modifié
       // Utilise Get_Index pour vérifier si l'élément doit être mis à jour
       function Add_Update(Element: TAppMessage): PAppMessage;
      
      
       // *** Suppression de pointeur
       // Libère et supprime le pointeur Index
       // Renvoi True si réussit, False si hors limite ou erreur
       function Delete(Index: integer): boolean; overload;

       // Cherche Element avec Get_Index et supprime LE
       // PREMIER pointeur trouvé, renvoi True si réussit
       function Delete(Element: string): boolean; overload;

      
       // *** Effacement de la liste de pointeur
       procedure Clear; override;
      
      
       // *** Requete sur la liste de pointeur
       function Get_Index(const Element: string): integer;
       function Get_Pointeur(const Element: string): PAppMessage;
       function Get_Item(Index: integer): TAppMessage;
       property Itemx[Index: integer]: TAppMessage read GetItemx;
      

      
       {--------------------------------------------------}
       {Procédures et fonctions spécialisées de la classes}
       // Destructeur
       destructor Destroy; override;
       constructor Create;
    end;


   function mamOrdreStrToType(Ordre: string): TOGOrdre;
   function mamIsAttackGroupee(Ordre: string): boolean;

   function mamDirectionToStr(Direction: TOGDirection): string;
   function mamOrdreToStr(Ordre: TOGOrdre): string;

   function mamCalculNbVaisseauxOwnFlotte(Content: string): integer;
   function mamCalculNbVaisseauxOwnFlotteV73c(Content: string): integer;
   //function mamPAppMessageToTAppMessageDejaAverti(pe: PAppMessage): TAppMessageDejaAverti;

implementation


(*
function mamPAppMessageToTAppMessageDejaAverti(pe: PAppMessage): TAppMessageDejaAverti;
begin
   Result.Depart         := pe.Depart;
   Result.Arrivee        := pe.Arrivee;
   Result.NbVaisseau     := pe.NbVaisseau;
   Result.VaisseauxStr   := pe.VaisseauxStr;
   Result.NbAffichageMsg := 0;
   Result.HaveBeenAverti := false;

   Result.MsgStr := pe.Msg;
   Result.DateLastAffichage := 0;
   
end;
*)



function mamCalculNbVaisseauxOwnFlotteV73c(Content: string): integer;
label lDoIt;
var xPos: integer;
    sNb : string;
    iNb: integer;
    sCurrVaisseau: string;
    bHasFinalize: boolean;
begin
   // Grand transporteur 12; Croiseur 15; Vaisseau de bataille 40


   Result := 0;
   Content := trim(Content);
   bHasFinalize := false;

   xPos := pos(';', Content);

   if xPos = 0 then begin
      sCurrVaisseau := Content;

   end;

   while (xPos <> 0) do begin
       sCurrVaisseau := copy(Content, 1, xPos - 1);
       System.Delete(Content, 1, xPos);

lDoIt:
       xPos := LastDelimiter(' ', sCurrVaisseau);

       if xPos = 0 then begin
          // impossible...
       end else begin
          sNb := copy(sCurrVaisseau, xPos + 1, maxint);
       end;

       iNb := StrToIntDef(sNb, 0);
       Inc(Result, iNb);

       xPos := pos(';', Content);
   end;

   if bHasFinalize then exit;

   bHasFinalize := true;
   sCurrVaisseau := Content;
   goto lDoIt;

end;



function mamCalculNbVaisseauxOwnFlotte(Content: string): integer;
var xPos: integer;
    sNb : string;
    iNb: integer;
begin
   // Grand transporteur:5 Croiseur:5 Vaisseau de bataille:29 Bombardier:1 Destructeur:5
   // On extrait le nombre après chaque ':' et on les ajoutes

   Result := 0;

   xPos := pos(':', Content);

   while (xPos <> 0) do begin
       System.Delete(Content, 1, xPos);

       xPos := pos(' ', Content);
       if xPos = 0 then begin
          sNb := Content;
          Content := '';
       end else begin
          sNb := copy(Content, 1, xPos - 1);
          System.Delete(Content, 1, xPos);
       end;

       iNb := StrToIntDef(sNb, 0);
       Inc(Result, iNb);

       xPos := pos(':', Content);
   end;


end;


function mamOrdreToStr(Ordre: TOGOrdre): string;
begin

    case Ordre of
        ooNeant: Result := LangParsing.GetData('aff_Inconnu', 'Inconnu');
        ooAttaquer: Result := LangParsing.GetData('aff_OrdreAttaquer', 'Attaquer');

        ooTransport: Result := LangParsing.GetData('aff_OrdreTransport', 'Transport');
        ooExploiter: Result := LangParsing.GetData('aff_OrdreExploiter', 'Exploiter');

        ooEspionner: Result := LangParsing.GetData('aff_OrdreEspionner', 'Espionner');
        ooBaser: Result := LangParsing.GetData('aff_OrdreBaser', 'Baser');
        ooColoniser: Result := LangParsing.GetData('aff_OrdreColoniser', 'Coloniser');

        else Result := LangParsing.GetData('aff_Invalide', 'Invalide');
    end;

end;

function mamIsAttackGroupee(Ordre: string): boolean;
begin
    Result := SameText(Ordre, LangParsing.GetData('vuegen_OrdreAttaquerGroupe', 'Attaque groupée'));
end;

function mamOrdreStrToType(Ordre: string): TOGOrdre;
var xPos: integer;
begin

   Ordre := trim(Ordre);



   if SameText(Ordre, LangParsing.GetData('vuegen_OrdreTransporter', 'Transporter')) or SameText(Ordre, LangParsing.GetData('flotte_OrdreTransport', 'Transport')) then begin
      Result := ooTransport;

   end else if SameText(Ordre, LangParsing.GetData('vuegen_OrdreStationner', 'Stationner')) or SameText(Ordre, LangParsing.GetData('flotte_OrdreBaser', 'Baser')) then begin
      Result := ooBaser;

   end else if SameText(Ordre, LangParsing.GetData('vuegen_OrdreExploiter', 'Exploiter')) or SameText(Ordre, LangParsing.GetData('flotte_OrdreExploiter', 'Exploiter')) then begin
      Result := ooExploiter;

   end else if SameText(Ordre, LangParsing.GetData('vuegen_OrdreEspionnage', 'Espionnage')) or SameText(Ordre, LangParsing.GetData('flotte_OrdreEspionner', 'Espionner')) then begin
      Result := ooEspionner;

   end else if SameText(Ordre, LangParsing.GetData('vuegen_OrdreAttaquer', 'Attaquer')) or SameText(Ordre, LangParsing.GetData('flotte_OrdreAttaquer', 'Attaquer')) then begin
      Result := ooAttaquer;

   end else if SameText(Ordre, LangParsing.GetData('vuegen_OrdreAttaquerGroupe', 'Attaque groupée')) then begin
      Result := ooAttaquer;

   end else if SameText(Ordre, LangParsing.GetData('vuegen_OrdreColoniser', 'Coloniser')) or SameText(Ordre, LangParsing.GetData('flotte_OrdreColoniser', 'Coloniser')) then begin
      Result := ooColoniser;



   end else
      Result := ooNeant;


end;


function mamDirectionToStr(Direction: TOGDirection): string;
begin

    case Direction of
        odNeant: Result := LangParsing.GetData('aff_Inconnu', 'Inconnu');
        odRetour: Result := LangParsing.GetData('aff_DirectionRetour', 'Retour');
        odAller: Result := LangParsing.GetData('aff_DirectionAller', 'Aller');
        else Result := LangParsing.GetData('aff_Invalide', 'Invalide');
    end;

end;








{*******************************************************************************
 ******************************************************************************* 
 **               TCollectionAppMessageDejaAverti                                     **
 *******************************************************************************
 *******************************************************************************}


(*
constructor TCollectionAppMessageDejaAverti.Create;
begin
    
    // Héritage
    InHerited Create;
    
    
    
    // Code pour l'initialisation ici
    
    
end;

destructor TCollectionAppMessageDejaAverti.Destroy;
begin
    // Implémenter le code avant l'héritage de la méthode
    // C'est à dire ici
    
   
    // On appelle NOTRE clear qui lui-même appelle NOTRE Delete qui libère l'espace mémoire
    // avant d'enlever le pointeur de la TList
    // L'héritage de Destroy appelle Clear, mais es-ce le notre ou celui de la classe de base ?
    Clear;
    
    
    // Héritage
    InHerited Destroy;
end;


procedure TCollectionAppMessageDejaAverti.Clear;
var i: integer;
begin

    if Count > 0 then begin
        For i := Count -1 downto 0 do
            Delete(i);
    end;
    
    inherited Clear;
end;


function TCollectionAppMessageDejaAverti.Get_Pointeur(const Element: string): PAppMessageDejaAverti;
var i: integer;
begin

   Result := nil;
   
   i := Get_Index(Element);
   if i < 0 then exit;
   Result := Items[i];

end;



function TCollectionAppMessageDejaAverti.AlreadyExists(Element: PAppMessage): boolean;
var n: TAppMessageDejaAverti;
begin
   n := mamPAppMessageToTAppMessageDejaAverti(Element);
   Result := AlreadyExists(n);
end;

function TCollectionAppMessageDejaAverti.AlreadyExists(Element: TAppMessageDejaAverti): boolean;
var i: integer;
    pElement: PAppMessageDejaAverti;
begin

   Result := false;

   if Count <= 0 then exit;


   for i := 0 to Count - 1 do begin

      pElement := Items[i];
      
      if CompareLocation(pElement.Depart, Element.Depart) then begin
         if CompareLocation(pElement.Arrivee, Element.Arrivee) then begin
            if pElement.NbVaisseau = Element.NbVaisseau then begin
               if SameText(pElement.VaisseauxStr, Element.VaisseauxStr) then begin
                  Result := true;
                   exit;
               end;
            end;
         end;
      end;
      
   end;

end;


function TCollectionAppMessageDejaAverti.Get_Index(const Element: string): integer;
var i: integer;
    xEle, xTest: string;
    pElement: PAppMessageDejaAverti;
begin

   Result := -1;

   if Count <= 0 then exit;
   xEle := lowercase(Element);

   for i := 0 to Count - 1 do begin

      pElement := Items[i];          {### ### ### ### ### ### ### ### ### ### ### ### ### ### }
      xTest := pElement^.VaisseauxStr;        {### Neccessite adpation en fonction du type record  ### }
      xTest := lowercase(xTest);     {### ### ### ### ### ### ### ### ### ### ### ### ### ### }


      if xEle = xTest then begin
         Result := i;
         exit;
      end;
   end;


end;

function TCollectionAppMessageDejaAverti.Add_Update(Element: TAppMessageDejaAverti): PAppMessageDejaAverti;
var i : integer;
begin
     
     Result := nil;
                                         {### ### ### ### ### ### ### ### ### ### ### ### ### ### }
     i := Get_Index(Element.VaisseauxStr);        {### Neccessite adpation en fonction du type record  ### }
                                         {### ### ### ### ### ### ### ### ### ### ### ### ### ### }
     if i < 0 then begin 
        // L'élément n'existe pas, l'ajoute
        Result  := Add(Element);
     end else begin
        // L'élément existe déjà, le met à jour
        Result  := Items[i];     // Obtient le pointeur
        Result^ := Element;
     end;
     
end;




function TCollectionAppMessageDejaAverti.Get_Item(Index: integer): TAppMessageDejaAverti;
var pElement: PAppMessageDejaAverti;
begin

     if Index < 0 then exit;
     if Index >= Count then exit;

     pElement := Items[Index];     // Obtient le pointeur
     Result := pElement^;

end;

function TCollectionAppMessageDejaAverti.Delete(Index: integer): boolean;
var pElement: PAppMessageDejaAverti;
begin

    Result := false;

    if (Index < 0) or (Index >= Count) then
       // Hors limite
       exit;


    // Obtient le pointeur
    pElement := Items[Index];

    if pElement <> nil then
       // Libére la mémoire créée lors de l'ajout
       Dispose(pElement);

    // Supprime le pointeur de la liste
    inherited Delete(Index);

    // Met le resultat à True
    Result := true;

end;

function TCollectionAppMessageDejaAverti.Delete(Element: string): boolean;
var i : integer;
begin

    Result := false;
    i      := Get_Index(Element);

    if i >= 0 then begin
       // Element trouvé
       // Le supprime
       Delete(i);

       // Même si la suppression Echoue on renvoi True
       // Car l'élément a été trouvé
       Result := true;
    end;
end;


function TCollectionAppMessageDejaAverti.Add(Element: TAppMessageDejaAverti): PAppMessageDejaAverti;
var pElement: PAppMessageDejaAverti;
begin
    
    Result := nil;
    
    New(pElement);          // Créer l'espace mémoire requis
    pElement^ := Element;   // Recopie les données dans l'emplacement pointé
    
    try
       inherited Add(pElement);  // Ajoute le pointeur à la liste
       Result := pElement;
    except
       Result := nil;
    end;
    
    // Pour libérer la mémoire occupé par l'élément pointer:  Dispose(pElement);

end;

// Simple ajout de pointeur
procedure TCollectionAppMessageDejaAverti.SimpleAdd(Pointeur: PAppMessageDejaAverti);
begin
    
    inherited Add(Pointeur);  // Ajoute le pointeur à la liste
    
end;

function TCollectionAppMessageDejaAverti.GetItemx(Index: integer): TAppMessageDejaAverti;
var pElement: PAppMessageDejaAverti;
begin

   if Count < 0 then exit;
   if Index >= Count then exit;

   pElement := Items[Index];
   Result := pElement^;

end;
*)



{*******************************************************************************
 ******************************************************************************* 
 **               TCollectionAppMessage                                     **
 *******************************************************************************
 *******************************************************************************}


constructor TCollectionAppMessage.Create;
begin
    
    // Héritage
    InHerited Create;
    
    
    
    // Code pour l'initialisation ici
    
    
end;

destructor TCollectionAppMessage.Destroy;
begin
    // Implémenter le code avant l'héritage de la méthode
    // C'est à dire ici
    
   
    // On appelle NOTRE clear qui lui-même appelle NOTRE Delete qui libère l'espace mémoire
    // avant d'enlever le pointeur de la TList
    // L'héritage de Destroy appelle Clear, mais es-ce le notre ou celui de la classe de base ?
    Clear;
    
    
    // Héritage
    InHerited Destroy;
end;


procedure TCollectionAppMessage.Clear;
var i: integer;
begin

    if Count > 0 then begin
        For i := Count -1 downto 0 do
            Delete(i);
    end;
    
    inherited Clear;
end;


function TCollectionAppMessage.Get_Pointeur(const Element: string): PAppMessage;
var i: integer;
begin

   Result := nil;
   
   i := Get_Index(Element);
   if i < 0 then exit;
   Result := Items[i];

end;


function TCollectionAppMessage.Get_Index(const Element: string): integer;
var i: integer;
    xEle, xTest: string;
    pElement: PAppMessage;
begin

   Result := -1;

   if Count <= 0 then exit;
   xEle := lowercase(Element);

   for i := 0 to Count - 1 do begin

      pElement := Items[i];          {### ### ### ### ### ### ### ### ### ### ### ### ### ### }
      xTest := pElement^.Msg;        {### Neccessite adpation en fonction du type record  ### }
      xTest := lowercase(xTest);     {### ### ### ### ### ### ### ### ### ### ### ### ### ### }


      if xEle = xTest then begin
         Result := i;
         exit;
      end;
   end;


end;

function TCollectionAppMessage.Add_Update(Element: TAppMessage): PAppMessage;
var i : integer;
begin
     
     Result := nil;
                                         {### ### ### ### ### ### ### ### ### ### ### ### ### ### }
     i := Get_Index(Element.Msg);        {### Neccessite adpation en fonction du type record  ### }
                                         {### ### ### ### ### ### ### ### ### ### ### ### ### ### }
     if i < 0 then begin 
        // L'élément n'existe pas, l'ajoute
        Result  := Add(Element);
     end else begin
        // L'élément existe déjà, le met à jour
        Result  := Items[i];     // Obtient le pointeur
        Result^ := Element;
     end;
     
end;




function TCollectionAppMessage.Get_Item(Index: integer): TAppMessage;
var pElement: PAppMessage;
begin

     if Index < 0 then exit;
     if Index >= Count then exit;

     pElement := Items[Index];     // Obtient le pointeur
     Result := pElement^;

end;

function TCollectionAppMessage.Delete(Index: integer): boolean;
var pElement: PAppMessage;
begin

    Result := false;

    if (Index < 0) or (Index >= Count) then
       // Hors limite
       exit;


    // Obtient le pointeur
    pElement := Items[Index];

    if pElement <> nil then
       // Libére la mémoire créée lors de l'ajout
       Dispose(pElement);

    // Supprime le pointeur de la liste
    inherited Delete(Index);

    // Met le resultat à True
    Result := true;

end;

function TCollectionAppMessage.Delete(Element: string): boolean;
var i : integer;
begin

    Result := false;
    i      := Get_Index(Element);

    if i >= 0 then begin
       // Element trouvé
       // Le supprime
       Delete(i);

       // Même si la suppression Echoue on renvoi True
       // Car l'élément a été trouvé
       Result := true;
    end;
end;


function TCollectionAppMessage.Add(Element: TAppMessage): PAppMessage;
var pElement: PAppMessage;
begin
    
    Result := nil;
    
    New(pElement);          // Créer l'espace mémoire requis
    pElement^ := Element;   // Recopie les données dans l'emplacement pointé
    
    try
       inherited Add(pElement);  // Ajoute le pointeur à la liste
       Result := pElement;
    except
       Result := nil;
    end;
    
    // Pour libérer la mémoire occupé par l'élément pointer:  Dispose(pElement);

end;

// Simple ajout de pointeur
procedure TCollectionAppMessage.SimpleAdd(Pointeur: PAppMessage);
begin
    
    inherited Add(Pointeur);  // Ajoute le pointeur à la liste
    
end;

function TCollectionAppMessage.GetItemx(Index: integer): TAppMessage;
var pElement: PAppMessage;
begin

   if Count < 0 then exit;
   if Index >= Count then exit;

   pElement := Items[Index];
   Result := pElement^;

end;

end.
